package com.xieman.anti.replay.aspect;

import com.xieman.anti.replay.annotation.XMAntiReplay;
import com.xieman.anti.replay.props.ReplayProperties;
import com.xieman.anti.replay.utils.ConvertUtils;
import com.xieman.anti.replay.utils.SpringUtils;
import com.xieman.anti.replay.utils.StringUtils;
import com.xieman.anti.replay.validator.AntiReplayValidator;
import com.xieman.anti.replay.validator.SignatureValidator;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;



/**
 * @description 禁止重复请求切面
 * @author XQF.Sui
 * @date 2021/07/30 01:15
 */
@Order(value = 1)
@Aspect
@Component
public class AntiReplayAspect {

  private final ReplayProperties props;
  private final String servletContextPath;

  AntiReplayAspect(ReplayProperties props, Environment env) {
    this.props = props;
    this.servletContextPath = env.getProperty("server.servlet.context-path");
  }

  @Around(value = "@annotation(narutoSecurity)")
  public Object around(ProceedingJoinPoint point, XMAntiReplay narutoSecurity)
          throws Throwable {

    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
    if (narutoSecurity.checkSignature()) {
      SignatureValidator.builder().data(request).execute();
    }

    // 禁止重放验证
    if (narutoSecurity.antiReplay()) {
      // 请求路径
      String targetUrl = StringUtils.replace(request.getRequestURI(), servletContextPath, "");

      try (AntiReplayValidator.AntiReplayWorker worker =
                   AntiReplayValidator.builder()
                           .methodName(SpringUtils.getMethodName(point))
                           .nonce(request.getHeader(props.getHeaderKey().getNonce()))
                           .url(request.getHeader(props.getHeaderKey().getUrl()))
                           .targetUrl(targetUrl)
                           .timestamp(
                                   ConvertUtils.StringToLong(
                                           request.getHeader(props.getHeaderKey().getTimestamp())))) {
        worker.execute();
        System.out.println("success");
        return point.proceed();
      }
    }

    return point.proceed();
  }

  private ServletRequestAttributes getServletRequestAttributes() {
    return (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
  }
}
